package main

import (
	"encoding/binary"
	"fmt"
	"net"
	"time"
)

const (
	// 空开设备的 IP 地址和端口号
	deviceIp   = "192.168.1.100"
	devicePort = 12345

	// UDP 通讯协议的版本号
	protocolVersion = 0xF1
	// 控制指令的命令 ID
	closeCmd = 0xA1
	tripCmd  = 0xA2
)

// 构造控制指令的数据包
func makeCtrlCmd(cmdId byte, nodeId byte) []byte {
	// 数据包长度为 16 字节的消息头 + 1 字节的指令参数 + 1 字节的节点号
	data := make([]byte, 18)

	// 设置消息头
	data[0] = protocolVersion
	data[1] = 0xD3 // D3 消息 ID
	data[2] = cmdId
	data[3] = 0x00                                   // 指令参数，此处无实际意义
	binary.BigEndian.PutUint16(data[4:6], uint16(2)) // 数据长度
	binary.BigEndian.PutUint16(data[6:8], uint16(1)) // 序列号，此处为示例值
	data[8] = 0x98                                   // MAC 地址，此处为示例值
	data[9] = 0xCC
	data[10] = 0x4D
	data[11] = 0x00
	data[12] = 0x0F // 时区，此处为示例值
	data[13] = 0x51 // HOST ID，此处为示例值
	data[14] = 0x00 // 保留
	data[15] = 0x00 // 保留
	data[16] = 0x00 // 时间戳，此处为示例值
	data[17] = 0x00 // 时间戳，此处为示例值

	// 设置指令参数和节点号
	data[18] = 0x00 // 指令参数，此处无实际意义
	data[19] = nodeId

	return data
}

// sendCtrlCmd
func sendCtrlCmd(cmdId byte, nodeId byte) error {
	// 创建 UDP 连接
	conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", deviceIp, devicePort))
	if err != nil {
		return err
	}
	defer conn.Close()

	// 构造控制指令的数据包
	data := makeCtrlCmd(cmdId, nodeId)

	// 发送数据包
	_, err = conn.Write(data)
	if err != nil {
		return err
	}

	// 等待接收响应数据包
	buffer := make([]byte, 1024)
	_, err = conn.Read(buffer)
	if err != nil {
		return err
	}

	// 解析响应数据包
	if buffer[1] == 0xD3 && buffer[3] == 0x00 {
		fmt.Printf("控制指令 %s 成功\n", map[byte]string{closeCmd: "合闸", tripCmd: "分闸"}[cmdId])
	} else {
		fmt.Printf("控制指令 %s 失败\n", map[byte]string{closeCmd: "合闸", tripCmd: "分闸"}[cmdId])
	}

	return nil
}

func main() {
	// 发送合闸指令
	err := sendCtrlCmd(closeCmd, 0x01) // 假设节点号为 0x01
	if err != nil {
		fmt.Println("发送合闸指令失败:", err)
		return
	}

	// 等待一段时间
	time.Sleep(5 * time.Second)

	// 发送分闸指令
	err = sendCtrlCmd(tripCmd, 0x01) // 假设节点号为 0x01
	if err != nil {
		fmt.Println("发送分闸指令失败:", err)
		return
	}
}
